package clases;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import es.deusto.ingenieria.is.csp.algorithms.CSPAlgorithm;
import es.deusto.ingenieria.is.csp.formulation.CSPProblem;
import es.deusto.ingenieria.is.csp.formulation.Constraint;
import es.deusto.ingenieria.is.csp.formulation.Variable;

public class ProblCriptaddition extends CSPProblem<Integer> {

	private int numOperands;
	private int columns;
	private boolean leadingDigit;
	private Alldiff todasDiferentes;
	private LeadDigitConstraint ultimoDigito;
	private List<ColumnConstraint> listaColumnConstraints;
	private List<Variable<Integer>> variables;
	private FormulaReader additionpuzzle;
	private List<Integer> domain;
	private List<Integer> auxiliarydomain;
	private String resultado;
	private List<Constraint<Integer>> constraints = new ArrayList<Constraint<Integer>>();

	public ProblCriptaddition(int operands, int columns, List<String> words, String resultado) {
		numOperands = operands;
		this.columns = columns;
		this.resultado = resultado;
		domain = createDomain();
		auxiliarydomain = createAuxiliaryDomain();

		for (String word : words) {
			for (int i = 0; i < word.length(); i++) {
				String letraString = String.valueOf(word.charAt(i));
				Letter letra = null;
				if (!containsVariable(letraString)) {
					letra = new Letter(letraString, domain);
					letra.addLocation(i + 1, 1, 0);
					variables.add(letra);
				}
				else {
					letra = (Letter) getVariableNamed(letraString);
					letra.incrementEnOperandos(i + 1);
				}
			}
		}

		for (int i = 0; i < resultado.length(); i++) {
			String letraString = String.valueOf(resultado.charAt(i));
			Letter letra = null;
			if (!containsVariable(letraString)) {
				letra = new Letter(letraString, domain);
				letra.addLocation(i + 1, 0, 1);
				variables.add(letra);
			}
			else {
				letra = (Letter) getVariableNamed(letraString);
				letra.incrementEnResultado(i + 1);
			}
		}
		createConstraints();
	}

	public void createConstraints() {
		for (int i = 0; i < resultado.length(); i++) {
			AuxiliaryVar leftAux = new AuxiliaryVar("X" + String.valueOf(i + 1), auxiliarydomain);
			AuxiliaryVar rightAux = new AuxiliaryVar("X" + String.valueOf(i + 2), auxiliarydomain);
			constraints.add(new ColumnConstraint(String.valueOf(i), getVariables(), leftAux, rightAux));
		}
		constraints.add(new Alldiff("allDiff", getVariables()));
		constraints.add(new LeadDigitConstraint("leadDigit", getVariables()));
	}

	public boolean containsVariable(String name) {
		List<Variable<Integer>> listaVariables = getVariables();
		for (Variable<Integer> variable : listaVariables) {
			if (variable.getName().equals(name)) {
				return true;
			}
		}
		return false;
	}

	public Variable<Integer> getVariableNamed(String name) {
		List<Variable<Integer>> listaVariables = getVariables();
		for (Variable<Integer> variable : listaVariables) {
			if (variable.getName().equals(name)) {
				return variable;
			}
		}
		return null;
	}

	public List<Integer> createDomain() {
		List<Integer> domain = new ArrayList<Integer>();
		for (int i = 0; i < 10; i++) {
			domain.add(i);
		}
		return domain;
	}

	public List<Integer> createAuxiliaryDomain() {
		List<Integer> auxiliarydomain = new ArrayList<Integer>();
		for (int i = 0; i < 10; i++) {
			auxiliarydomain.add(i);
		}
		return auxiliarydomain;
	}

	@Override
	public String toString() {
		return "Problema Criptosuma";
	}

	public static void main(String[] args) {

	}

	public void solve(CSPAlgorithm<Integer> algorithm) {
		SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss.S");
		Date beginDate = Calendar.getInstance().getTime();
		System.out.println("\n* Start '" + algorithm.getClass().getSimpleName() + "' (" + formatter.format(beginDate) + ")");
		boolean solutionFound = algorithm.solve(this);
		Date endDate = Calendar.getInstance().getTime();
		System.out.println("* End   '" + algorithm.getClass().getSimpleName() + "' (" + formatter.format(endDate) + ")");

		long miliseconds = (int) Math.abs(beginDate.getTime() - endDate.getTime());
		long seconds = miliseconds / 1000;
		miliseconds %= 1000;
		long minutes = seconds / 60;
		seconds %= 60;
		long hours = minutes / 60;
		minutes %= 60;

		String time = "\n* Serach lasts: ";
		time += (hours > 0) ? hours + " h " : " ";
		time += (minutes > 0) ? minutes + " m " : " ";
		time += (seconds > 0) ? seconds + "s " : " ";
		time += (miliseconds > 0) ? miliseconds + "ms " : " ";

		System.out.println(time);

		if (solutionFound) {
			System.out.println("\n- :-) Solution found!");
			System.out.println("\n" + this);
		}
		else {
			System.out.println("\n- :-( Unable to find the solution!");
		}
	}

}
